require.config({
    packages: [
        {
            name: 'zrender',
            location: 'build',
            main: 'zrender'
        }
    ]
});

document.addEventListener("click", function (e) {
    if (!e.target || !e.target.parentElement) {
        return;
    }
    e = (e.target && e.target.nodeName == 'BUTTON') ? e.target : e.target.parentElement;
    if (!e.nodeName == 'BUTTON' || !e.classList.contains('toggle') || e.attributes['disabled']) {
        return;
    }
    e.classList.toggle("toggled");
    e.toggled = !e.toggled;
});


function PlayGround(zrender, CircleShape, PolylineShape, LineShape, click, main) {
    // 初始化zrender
    var zr = zrender.init(main);
    window.zr = zr;

    function _P(p, dx, dy) {
        return [p[0] + dx, p[1] + dy];
    }

    window.zr = zr;

    //拉杆
    var l = {
        a: [60, 100],
        b: [20, 120],
        c: [60, 140],
        d: [980, 100],
        e: [980, 140],
        f: [990, 104],
        g: [990, 136],
        h: [1010, 116],
        i: [1010, 124],
        j: [1050, 116],
        k: [1050, 124],
        l: [1070, 100],
        m: [1070, 140],
        n: [1030, 100],
        o: [1030, 140]
    };

    //基座
    var b = {
        a: [141, 330],
        b: [100, 350],
        c: [141, 370],
        d: [1000, 330],
        e: [1040, 350],
        f: [1000, 370]
    };

    //柱子
    var p = {
        a: [170, 40],
        b: [170, 400],
        c: [179, 30],
        d: [170, 20],
        e: [160, 30],
        f: [180, 410],
        g: [170, 420],
        h: [160, 410],
        i: [170, 360],
        c1: [170, 28],
        c2: [120, 150],
        c3: [60, 180],
        c4: [86, 106]
    };


    var ss = 0.65;

    var line = {
        stroke: "#3B5277",
        lineWidth: 8,
        lineCap: 'butt',
        shadowColor: "#000",
        shadowBlur: 3,
        lineJoin: "bevel",
        shadowOffsetX: 3,
        shadowOffsetY: 3,
    };

    var pline = {
        stroke: "#B47850",
        lineWidth: 8,
        lineCap: 'butt',
        shadowColor: "#000",
        shadowBlur: 3,
        lineJoin: "bevel",
        shadowOffsetX: 3,
        shadowOffsetY: 3,
    };
    var pline2 = {
        stroke: "rgba(180, 120, 80, 1)",
        lineWidth: 8,
        lineCap: 'butt',
        shadowColor: "#000",
        shadowBlur: 2,
        lineJoin: "bevel",
        shadowOffsetX: 2,
        shadowOffsetY: 2,
    };
    var pcircle = {
        stroke: "#337267",
        lineWidth: 8,
        lineCap: 'round',
        shadowColor: "#000",
        shadowBlur: 3,
        lineJoin: "bevel",
        shadowOffsetX: 3,
        shadowOffsetY: 3,
    };

    var fill = {
        fill: '#B49050',
        lineWidth: 0,
        lineCap: 'round',
        shadowColor: "#000",
        shadowBlur: 3,
        lineJoin: "bevel",
        shadowOffsetX: 3,
        shadowOffsetY: 3,
    };
    var pfill2 = {
        stroke: "#B49050",
        lineWidth: 8
    };
    var pback = {
        stroke: "rgba(250, 250, 250, 1)",
        fill: 'rgb(250, 250, 250)',
        lineWidth: 8,
        lineCap: 'butt'
    };
    var pfill = {
        stroke: "#337267",
        fill: '#337267',
        lineWidth: 0,
        lineCap: 'round',
        shadowColor: "#000",
        shadowBlur: 3,
        lineJoin: "bevel",
        shadowOffsetX: 3,
        shadowOffsetY: 3,
    };
    var fill2 = {
        stroke: "rgba(0, 0, 0, 1)",
        lineWidth: 60
    };
    var back = {
        fill: 'rgba(255, 0, 0, 0)',
        lineWidth: 0
    };
    var back2 = {
        fill: 'rgba(255, 0, 0, 1)',
        lineWidth: 0
    };

    var none = {
        stroke: "rgba(0, 0, 0, 0)",
        lineWidth: 0
    };

    //bg
    var bg = new PolylineShape({
        style: back,
        shape: {
            points: [[0, 0], [0, zr.getHeight()], [zr.getWidth(), zr.getHeight()], [zr.getWidth(), 0]]
        },
        zlevel: 0
    });
    window.bg = bg;
    zr.add(bg);

    //lever left
    zr.add(new PolylineShape({
        style: line,
        shape: {
            points: [_P(l.a, 1, 0), l.b, _P(l.c, 1, 0)],
            smooth: ss
        },
        zlevel: 10
    }));
    //lever back
    zr.add(new LineShape({
        style: line,
        shape: {
            x1: l.a[0],
            y1: l.a[1],
            x2: l.d[0],
            y2: l.d[1]
        },
        zlevel: 10
    }));
    //lever front
    zr.add(new LineShape({
        style: line,
        shape: {
            x1: l.c[0],
            y1: l.c[1],
            x2: l.e[0],
            y2: l.e[1]
        },
        zlevel: 100
    }));
    //lever handle back
    zr.add(new PolylineShape({
        style: line,
        shape: {
            points: [_P(l.d, -2, 0), l.f, l.h, l.j, l.l, l.n, l.j],
            smooth: ss
        },
        zlevel: 10
    }));
    zr.add(new PolylineShape({
        style: line,
        shape: {
            points: [_P(l.e, -2, 0), l.g, l.i, l.k, l.m, l.o, l.k],
            smooth: ss
        },
        zlevel: 100
    }));

    //base left
    zr.add(new PolylineShape({
        style: fill,
        shape: {
            points: [b.a, b.b, b.c],
            smooth: ss
        }
    }));
    //base body
    zr.add(new PolylineShape({
        style: fill,
        shape: {
            points: [
                b.a,
                b.c,
                b.f,
                b.d
            ],
            smooth: 0
        },
        zlevel: 100
    }));
    //base right
    zr.add(new PolylineShape({
        style: fill,
        shape: {
            points: [_P(b.d, -1, 0), b.e, _P(b.f, -1, 0)],
            smooth: ss
        },
        zlevel: 101
    }));

    var pillars = initPillars(p, 100, 130, pline, pfill, pcircle, pback);

    function initAll(zr, pillars, isUp) {
        for (var i = 0; i <= 8; i++) {
            removePillars(zr, pillars, i);
            addPillars(zr, pillars, i, isUp);
        }
    }

    click = click || function (i) {
        movePillars(zr, pillars, i);
    }
    function eventHandler(e) {
        var x = e.offsetX / outer.offsetWidth * 1200;
        x -= 90;
        var i = -1;
        if (x > 0) {
            i = Math.floor(x / 100);
        }
        if (i < 0 || i > 8) {
            return;
        }
        switch (e.type) {
            case 'click':
                click(i);
                break;
            case 'mousemove':
                highLightPillars(zr, pillars, i);
                break;
        }
    }


    zr.on("mousemove", eventHandler);
    zr.on("click", eventHandler);

    function addPillars(zr, pillars, k, isUp) {
        var p = isUp ? pillars.up(k) : pillars.down(k);
        for (var i = 0; i < p.length; i++) {
            zr.add(p[i]);
        }
    }

    function removePillars(zr, pillars, i) {
        var p = pillars.get(i);
        for (var i = 0; i < p.length; i++) {
            zr.remove(p[i]);
        }
    }


    function movePillars(zr, pillars, k) {
        var r = doMovePillars(zr, pillars, k);
        if (r === false) {
            notAllowed();
        }
    }

    function doMovePillars(zr, pillars, k) {
        if (k != 0) {
            if (!pillars.get(k - 1).isUp) {
                return false;
            }
            for (var i = k - 2; i >= 0; i--) {
                var a = pillars.get(i);
                if (a.isUp) {
                    return false;
                }
            }
        }
        forceMove(zr, pillars, k);
        return true;
    }

    function forceMove(zr, pillars, i) {
        var a = pillars.get(i);
        removePillars(zr, pillars, i);
        addPillars(zr, pillars, i, !a.isUp);
    }


    function highLightPillars(zr, pillars, k, color) {
        color = color || "#898902";
        if (zr.currentPillar == k) {
            return;
        }
        zr.currentPillar = k;
        for (var i = 0; i <= 8; i++) {
            var c = (k == i ? "#898902" : "black");
            var p = pillars.get(i);
            for (var j = 0; j <= 7; j++) {
                p[j].setStyle('shadowColor', c);
            }
        }
        zr.refresh();
    }

    function notAllowed() {
        bg.animateTo({ style: { fill: 'rgb(255,150,150)' } },
            200, 0, 'quadraticIn', function () {
                bg.animateTo({ style: { fill: 'white' } },
                    400, 400, 'quadraticOut');
            })
    }

    window.cheerController = false;

    var cheerColors = ['yellow', 'fuchsia', 'red',
        'gray', 'olive', 'purple',
        'maroon', 'aqua', 'teal',
        'lime', 'green', 'blue'];

    function cheer(i) {
        i = (i || i == 0) ? i : 0;
        bg.animateTo({ style: { fill: cheerColors[i] } },
            100, 0, 'quadraticIn');
        setTimeout(function () {
            if (cheerController) {
                i++;
                if (i >= cheerColors.length) {
                    i = 0;
                }
                cheer(i);
            } else {
                bg.animateTo({ style: { fill: 'white' } });
            }
        }, 100);
    }

    function getInitStyle(type) {
        switch (type) {
            case 'pb':
                return pfill;
            case 'pb1':
                return pback;
            case 'pb2':
                return pline2;
            case 'pb3':
                return pfill2;
            case 'pl':
            case 'pt2':
                return pline;
            case 'pc1':
            case 'pc2':
                return pcircle;
            default:
                return none;
        }
    }

    function initPillars(positions, dw, dh, pline, pfill, pcircle, pback) {
        var pillars = [];
        var ss = 0.65;
        var cal = function (p, dw, dh) {
            var pl, pt1, pt2, pb, pc1, pc2;
            //pillar long
            pl = new LineShape({
                style: getInitStyle('pl'),
                shape: {
                    x1: p.a[0] + dw,
                    y1: p.a[1] + dh + 2,
                    x2: p.b[0] + dw,
                    y2: p.b[1] + dh
                },
                zlevel: 51,
                type: "pl"
            });
            //pillar top 2
            pt2 = new PolylineShape({
                style: getInitStyle('pt2'),
                shape: {
                    points: [
                        [p.a[0] + dw, p.a[1] + dh],
                        [p.c[0] + dw, p.c[1] + dh],
                        [p.d[0] + dw, p.d[1] + dh],
                        [p.e[0] + dw, p.e[1] + dh],
                        [p.a[0] + dw, p.a[1] + dh],
                        [p.c[0] + dw, p.c[1] + dh]
                    ],
                    smooth: 0.5
                },
                zlevel: 50,
                type: "pt2"
            });
            //pillar bottom
            pb = new PolylineShape({
                style: getInitStyle('pb'),
                shape: {
                    points: [
                        [p.b[0] + dw, p.b[1] + dh - 4],
                        [p.f[0] + dw + 4, p.f[1] + dh],
                        [p.g[0] + dw, p.g[1] + dh + 4],
                        [p.h[0] + dw - 4, p.h[1] + dh],
                        [p.b[0] + dw, p.b[1] + dh - 4]
                    ],
                    smooth: ss
                },
                zlevel: 52,
                type: "pb"
            });
            //pillar circle front
            pc1 = new PolylineShape({
                style: getInitStyle('pc1'),
                shape: {
                    points: [
                        [p.c1[0] + dw + 1, p.c1[1] + dh + 2],
                        [p.c2[0] + dw, p.c2[1] + dh],
                        [p.c3[0] + dw, p.c3[1] + dh]
                    ],
                    smooth: 1
                },
                zlevel: 150,
                type: "pc1"
            });
            //pillar circle back
            pc2 = new PolylineShape({
                style: getInitStyle('pc2'),
                shape: {
                    points: [
                        [p.c1[0] + dw, p.c1[1] + dh],
                        [p.c4[0] + dw, p.c4[1] + dh],
                        [p.c3[0] + dw, p.c3[1] + dh]
                    ],
                    smooth: 1
                },
                draggable: true,
                zlevel: 1,
                type: "pc2"
            });
            //pillar hole
            pb1 = new PolylineShape({
                style: getInitStyle('pb1'),
                shape: {
                    points: [
                        [p.i[0] + dw, p.i[1] - 14],
                        [p.i[0] + dw + 6, p.i[1] - 10],
                        [p.i[0] + dw, p.i[1] - 6],
                        [p.i[0] + dw - 6, p.i[1] - 10],
                        [p.i[0] + dw, p.i[1] - 14]
                    ],
                    smooth: 1
                },
                zlevel: 110,
                type: "pb1"
            });
            //pillar long front
            pb2 = new LineShape({
                style: getInitStyle('pb2'),
                shape: {
                    x1: p.i[0] + dw,
                    y1: p.i[1] - 40,
                    x2: p.i[0] + dw,
                    y2: p.i[1]
                },
                zlevel: 120,
                type: "pb2"
            });
            // pillar bottom base
            pb3 = new PolylineShape({
                style: getInitStyle('pb3'),
                shape: {
                    points: [
                        [p.i[0] + dw - 14, p.i[1] - 4],
                        [p.i[0] + dw, p.i[1] + 3],
                        [p.i[0] + dw + 14, p.i[1] - 4]
                    ],
                    smooth: ss
                },
                zlevel: 160,
                type: "pb3"
            });
            return [pl, pb3, pt2, pb, pc1, pc2, pb1, pb2];
        }


        return {
            get: function (i) {
                if (!pillars[i]) {
                    pillars[i] = cal(positions, dw * i, 0);
                    pillars[i].isUp = true;
                }
                return pillars[i];
            },
            up: function (i) {
                pillars[i] = cal(positions, dw * i, 0);
                pillars[i].isUp = true;
                return pillars[i];
            },
            down: function (i) {
                pillars[i] = cal(positions, dw * i, dh);
                pillars[i].isUp = false;
                return pillars[i];
            }
        }
    };

    return {
        init: function (up) {
            initAll(zr, pillars, up);
        },
        move: function (i) {
            return doMovePillars(zr, pillars, i);
        },
        forceMove: function (i) {
            forceMove(zr, pillars, i);
        },
        highLightPillars: function (i, color) {
            highLightPillars(zr, pillars, i, color);
        },
        notAllowed: notAllowed,
        cheer: function (stop) {
            cheerController = !stop;
            if (cheerController) {
                cheer();
            }
        },
        count: 9
    };

}


function Board(zrender, CircleShape, PolylineShape, LineShape) {

    var $ = function (s) {
        return document.getElementById(s);
    }

    var outer = $("outer");
    var main = $("main");
    var step = $('step');

    var resize = function () {
        var ratio = outer.offsetWidth / 1200;
        var scale = "scale(" + ratio + "," + ratio + ")";
        main.style.setProperty("transform", scale);
        main.style.setProperty("-ms-transform", scale);
        main.style.setProperty("-moz-transform", scale);
        main.style.setProperty("-webkit-transform", scale);
        main.style.setProperty("-o-transform", scale);
    }

    var doneFlag = false;
    var done = function () {
        doneFlag = true;
        playGround.cheer();
    }

    var click = function (i, force) {
        if (doneFlag) return init(playMode());
        if (nextLock() && force != 'force') return;
        playGround.cheer(true);
        if (gameMode()) {
            if (playGround.move(i)) {
                var r = game.toggle(i);
                step.innerHTML = game.counter;
                if ((r == 1 && !playMode()) || (r == -1 && playMode())) {
                    done();
                }
            } else {
                playGround.notAllowed();
            }
        } else {
            game.set(i);
            playGround.forceMove(i);
        }
    };

    var playGround = PlayGround(zrender, CircleShape, PolylineShape, LineShape, click, main);
    var game = "";

    function loop(cb, obj, reverse) {
        obj = obj || window;
        if (typeof cb == 'function') {
            for (var i = 0; i <= 8; i++) {
                if (cb.apply(obj, reverse ? 8 - i : i) === false) {
                    break;
                }
            }
            return reverse ? 8 - i : i;
        }
        return -1;
    }

    var init = function (up, noAsk) {
        if (!noAsk && !window.confirm("是否重置？")) {
            return;
        }

        playGround.init(up);
        playGround.cheer(true);
        game = new Game(playGround.count, up);
        window.g = game;
        window.p = playGround;

        step.innerHTML = game.counter;

        doneFlag = false;
    }
    var next = function (up) {
        if (doneFlag) return init(playMode());
        if (nextLock()) return;
        var s = game.setFrom(playGround.count, !up, false);
        if (s == -1) {
            step.innerHTML = "完成 " + step.innerHTML;
            done();
        }
        nextLock(true);
        playGround.highLightPillars(s);
        setTimeout(function () {
            playGround.highLightPillars(s, 'red');
            click(s, 'force');
            setTimeout(function () {
                playGround.highLightPillars(s);
                nextLock(false);
            }, 200);
        }, 200);
    }

    var gameBtn = $('game');

    var modeBtn = $('mode');
    var resetBtn = $('reset');

    var nextBtn = $('next');

    function nextLock(e) {
        if (e === undefined) {
            return gameBtn.attributes['disabled'];
        }
        if (e) {
            setGame(false);
            gameBtn.setAttribute('disabled', 'disabled');
        } else {
            setGame(gameMode());
            gameBtn.removeAttribute('disabled');
        }
    }

    function setGame(game) {
        if (!game) {
            modeBtn.setAttribute('disabled', 'disabled');
            resetBtn.setAttribute('disabled', 'disabled');

            nextBtn.setAttribute('disabled', 'disabled');
        } else {
            modeBtn.removeAttribute('disabled');
            resetBtn.removeAttribute('disabled');

            nextBtn.removeAttribute('disabled');
        }
    }

    function gameMode() {
        return !gameBtn.toggled;
    }

    function playMode() {
        return !modeBtn.toggled;
    }

    gameBtn.addEventListener("click", function () {
        setTimeout(function () {
            setGame(gameMode());
        }, 10);
    });

    modeBtn.addEventListener("click", function () {
        //setMode(!playMode());
    });

    resetBtn.addEventListener("click", function () {
        init(playMode());
    });

    nextBtn.addEventListener("click", function () {
        next(playMode());
    });


    init(true, true);

    resize();
    window.onresize = resize;
}

function Game(n, up) {
    up = (up === undefined) ? true : up;
    var inArray = typeof n == 'object' && n.push;
    var l = (typeof n == 'number' && n > 0) ? n : (
        inArray ? n.length : 9
    );
    this.counter = 0;
    this.all = [];
    window.all = this.all;
    if (inArray) {
        all = n;
    } else {
        for (var i = 0; i < l; i++) {
            this.all.push(up ? 1 : 0);
        }
    }
}

Game.prototype.toggle = function (i) {
    for (var j = 0; j < i - 2; j++) {
        if (this.isUp(j, true)) {
            throw ([arguments, all]);
        }
    }
    if (i - 1 >= 0) {
        if (this.isUp(i - 1, false)) {
            throw ([arguments, all]);
        }
    }
    this.counter++;
    var t = this.all + ">"
    this.set(i);
    console.log(t,
        "" + arguments[0] + "-" + (arguments[1] ? 1 : 0) + ">",
        this.all + "");
    return (this.all.indexOf(1) == -1) ? -1 : (this.all.indexOf(0) == -1) ? 1 : 0;
}


Game.prototype.isUp = function (i, up) {
    return this.all[i] == (up ? 1 : 0);
}
Game.prototype.set = function (i) {
    return this.all[i] = (this.isUp(i, false) ? 1 : 0);
}


Game.prototype.setFrom = function (last, up, play) {
    var i = last >= this.all.length ? this.all.length - 1 : last;
    for (; i >= 0; i--) {
        if (this.isUp(i, up)) {
            continue;
        }
        var next = this.setBefore(i, play);
        if (play) {
            this.toggle(i);
        } else {
            if (next >= 0) {
                return next;
            }
            return i;
        }
    }
    return -1;
}

Game.prototype.setBefore = function (i, play) {
    if (i == 0) {
        return -1;
    }
    if (!this.isUp(i - 1, true)) {
        if (play) {
            this.toggle(i - 1);
        } else {
            var next = this.setBefore(i - 1, play);
            if (next >= 0) {
                return next;
            }
            return i - 1;
        }
    }
    if (i == 1) {
        return 1;
    }
    return this.setFrom(i - 2, false, play);
}

require(
    [
        "zrender",
        'zrender/graphic/shape/Circle',
        "zrender/graphic/shape/Polyline",
        "zrender/graphic/shape/Line"
    ], function (zrender, CircleShape, PolylineShape, LineShape) {
        Board(zrender, CircleShape, PolylineShape, LineShape);
    });